import { Request, Response, NextFunction } from 'express';
import Joi from 'joi';
import { logger } from '../utils/logger';
import { checkPasswordStrength } from '../utils/password';

/**
 * 验证中间件工厂函数
 */
export const validate = (schema: Joi.ObjectSchema) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = schema.validate(req.body);
    
    if (error) {
      logger.warn('请求验证失败:', {
        path: req.path,
        method: req.method,
        errors: error.details.map(detail => ({
          field: detail.path.join('.'),
          message: detail.message,
          value: detail.context?.value
        }))
      });

      res.status(400).json({
        success: false,
        message: '请求参数验证失败',
        errors: error.details.map(detail => ({
          field: detail.path.join('.'),
          message: detail.message.replace(/"/g, '')
        }))
      });
      return;
    }

    // 将验证后的数据替换原始数据
    req.body = value;
    next();
  };
};

/**
 * 用户注册验证规则
 */
export const registerValidation = Joi.object({
  email: Joi.string()
    .email()
    .required()
    .messages({
      'string.email': '请输入有效的邮箱地址',
      'any.required': '邮箱是必填项'
    }),
  
  password: Joi.string()
    .min(6)
    .max(50)
    .required()
    .custom((value, helpers) => {
      const strengthCheck = checkPasswordStrength(value);
      if (!strengthCheck.isValid) {
        return helpers.error('password.weak', { feedback: strengthCheck.feedback });
      }
      return value;
    })
    .messages({
      'string.min': '密码至少需要6个字符',
      'string.max': '密码不能超过50个字符',
      'password.weak': '密码强度不足: {{#feedback}}',
      'any.required': '密码是必填项'
    }),
  
  name: Joi.string()
    .min(2)
    .max(50)
    .trim()
    .required()
    .messages({
      'string.min': '姓名至少需要2个字符',
      'string.max': '姓名不能超过50个字符',
      'any.required': '姓名是必填项'
    }),
  
  role: Joi.string()
    .valid('teacher', 'student')
    .default('teacher')
    .messages({
      'any.only': '角色只能是teacher或student'
    }),

  bio: Joi.string()
    .max(500)
    .allow('')
    .optional()
    .messages({
      'string.max': '个人简介不能超过500个字符'
    })
});

/**
 * 用户登录验证规则
 */
export const loginValidation = Joi.object({
  email: Joi.string()
    .email()
    .required()
    .messages({
      'string.email': '请输入有效的邮箱地址',
      'any.required': '邮箱是必填项'
    }),
  
  password: Joi.string()
    .required()
    .messages({
      'any.required': '密码是必填项'
    })
});

/**
 * 刷新令牌验证规则
 */
export const refreshTokenValidation = Joi.object({
  refreshToken: Joi.string()
    .required()
    .messages({
      'any.required': '刷新令牌是必填项'
    })
});

/**
 * 忘记密码验证规则
 */
export const forgotPasswordValidation = Joi.object({
  email: Joi.string()
    .email()
    .required()
    .messages({
      'string.email': '请输入有效的邮箱地址',
      'any.required': '邮箱是必填项'
    })
});

/**
 * 重置密码验证规则
 */
export const resetPasswordValidation = Joi.object({
  token: Joi.string()
    .required()
    .messages({
      'any.required': '重置令牌是必填项'
    }),
  
  newPassword: Joi.string()
    .min(6)
    .max(50)
    .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
    .required()
    .messages({
      'string.min': '密码至少需要6个字符',
      'string.max': '密码不能超过50个字符',
      'string.pattern.base': '密码必须包含至少一个大写字母、一个小写字母和一个数字',
      'any.required': '新密码是必填项'
    })
});

/**
 * 用户信息更新验证规则
 */
export const updateProfileValidation = Joi.object({
  name: Joi.string()
    .min(2)
    .max(50)
    .trim()
    .optional()
    .messages({
      'string.min': '姓名至少需要2个字符',
      'string.max': '姓名不能超过50个字符'
    }),
  
  bio: Joi.string()
    .max(500)
    .allow('')
    .optional()
    .messages({
      'string.max': '个人简介不能超过500个字符'
    }),

  avatar: Joi.string()
    .uri()
    .allow('')
    .optional()
    .messages({
      'string.uri': '头像必须是有效的URL地址'
    })
});

/**
 * 修改密码验证规则
 */
export const changePasswordValidation = Joi.object({
  currentPassword: Joi.string()
    .required()
    .messages({
      'any.required': '当前密码是必填项'
    }),
  
  newPassword: Joi.string()
    .min(6)
    .max(50)
    .required()
    .custom((value, helpers) => {
      const strengthCheck = checkPasswordStrength(value);
      if (!strengthCheck.isValid) {
        return helpers.error('password.weak', { feedback: strengthCheck.feedback });
      }
      return value;
    })
    .messages({
      'string.min': '新密码至少需要6个字符',
      'string.max': '新密码不能超过50个字符',
      'password.weak': '新密码强度不足: {{#feedback}}',
      'any.required': '新密码是必填项'
    })
});